using System;
using System.Collections.Generic;
using System.Linq;

using Godot;

public partial class Main : Node2D
{
    // 游戏配置
    [Export] public int GridWidth = 8;

    [Export] public int GridHeight = 8;
    [Export] public int TileSize = 90;
    [Export] public Vector2 BoardOffset = new Vector2(64, 64);

    // 预制场景
    [Export] public PackedScene TileScene;

    // 游戏状态
    private Tile[,] _tiles;

    private bool _isInputEnabled = true;
    private Tile _selectedTile;

    public override void _Ready()
    {
        InitializeBoard();
        FillBoard();
    }

    private void InitializeBoard()
    {
        _tiles = new Tile[GridWidth, GridHeight];

        for (var x = 0; x < GridWidth; x++)
        {
            for (var y = 0; y < GridHeight; y++)
            {
                //var tile = (Tile)TileScene.Instance();
                var tile = (Tile)ResourceLoader.Load<PackedScene>(TileScene.ResourcePath).Instantiate();
                AddChild(tile);

                tile.Position = new Vector2(
                    x * TileSize + BoardOffset.X,
                    y * TileSize + BoardOffset.Y
                );

                tile.GridPosition = new Vector2(x, y);
                //tile.Connect("TileSelected", this, nameof(OnTileSelected));
                tile.Connect("TileSelected", Callable.From<Tile>(c => OnTileSelected(c)));
                //EmitSignal("TileSelected", this, nameof(OnTileSelected));

                _tiles[x, y] = tile;
            }
        }
    }

    private void FillBoard()
    {
        var random = new Random();

        for (var x = 0; x < GridWidth; x++)
        {
            for (var y = 0; y < GridHeight; y++)
            {
                if (_tiles[x, y].Type == TileType.None)
                {
                    // 确保不会一开始就有匹配
                    TileType type;
                    do
                    {
                        type = (TileType)random.Next(1, Enum.GetValues(typeof(TileType)).Length);
                        _tiles[x, y].Type = type;
                    }
                    while (CheckMatchesAt(new Vector2(x, y)).Any());
                }
            }
        }
    }

    private async void OnTileSelected(Tile tile)
    {
        if (!_isInputEnabled) return;

        if (_selectedTile == null)
        {
            _selectedTile = tile;
            tile.Select();
        }
        else if (_selectedTile == tile)
        {
            _selectedTile.Deselect();
            _selectedTile = null;
        }
        else
        {
            if (AreAdjacent(_selectedTile, tile))
            {
                _isInputEnabled = false;

                // 交换方块
                await SwapTiles(_selectedTile, tile);

                // 检查匹配
                var matches = FindAllMatches();
                if (matches.Count > 0)
                {
                    await RemoveMatches(matches);
                    await FillEmptySpaces();

                    // 检查新的匹配
                    var newMatches = FindAllMatches();
                    while (newMatches.Count > 0)
                    {
                        await RemoveMatches(newMatches);
                        await FillEmptySpaces();
                        newMatches = FindAllMatches();
                    }
                }
                else
                {
                    // 如果没有匹配，交换回来
                    await SwapTiles(_selectedTile, tile);
                }

                _selectedTile.Deselect();
                _selectedTile = null;
                _isInputEnabled = true;
            }
            else
            {
                _selectedTile.Deselect();
                _selectedTile = tile;
                tile.Select();
            }
        }
    }

    private bool AreAdjacent(Tile a, Tile b)
    {
        return Math.Abs(a.GridPosition.X - b.GridPosition.X) +
               Math.Abs(a.GridPosition.Y - b.GridPosition.Y) == 1;
    }

    private async System.Threading.Tasks.Task SwapTiles(Tile a, Tile b)
    {
        // 更新网格位置
        var tempPos = a.GridPosition;
        a.GridPosition = b.GridPosition;
        b.GridPosition = tempPos;

        // 更新数组引用
        _tiles[(int)a.GridPosition.X, (int)a.GridPosition.Y] = a;
        _tiles[(int)b.GridPosition.X, (int)b.GridPosition.Y] = b;

        // 动画
        var tween = CreateTween();
        tween.Parallel().TweenProperty(a, "position", GetPositionFromGrid(b.GridPosition), 0.3f);
        tween.Parallel().TweenProperty(b, "position", GetPositionFromGrid(a.GridPosition), 0.3f);

        await ToSignal(tween, "finished");
    }

    private Vector2 GetPositionFromGrid(Vector2 gridPos)
    {
        return new Vector2(
            gridPos.X * TileSize + BoardOffset.X,
            gridPos.Y * TileSize + BoardOffset.Y
        );
    }

    private List<Tile> FindAllMatches()
    {
        var matches = new List<Tile>();

        for (var x = 0; x < GridWidth; x++)
        {
            for (var y = 0; y < GridHeight; y++)
            {
                var tile = _tiles[x, y];
                if (tile == null || tile.Type == TileType.None) continue;

                var tileMatches = CheckMatchesAt(tile.GridPosition);
                foreach (var match in tileMatches)
                {
                    if (!matches.Contains(match))
                    {
                        matches.Add(match);
                    }
                }
            }
        }

        return matches;
    }

    private List<Tile> CheckMatchesAt(Vector2 gridPos)
    {
        var matches = new List<Tile>();
        var tile = _tiles[(int)gridPos.X, (int)gridPos.Y];
        if (tile == null || tile.Type == TileType.None) return matches;

        // 检查水平匹配
        var horizontalMatches = new List<Tile> { tile };

        // 向左检查
        for (var x = (int)gridPos.X - 1; x >= 0; x--)
        {
            var otherTile = _tiles[x, (int)gridPos.Y];
            if (otherTile != null && otherTile.Type == tile.Type)
            {
                horizontalMatches.Add(otherTile);
            }
            else
            {
                break;
            }
        }

        // 向右检查
        for (var x = (int)gridPos.X + 1; x < GridWidth; x++)
        {
            var otherTile = _tiles[x, (int)gridPos.Y];
            if (otherTile != null && otherTile.Type == tile.Type)
            {
                horizontalMatches.Add(otherTile);
            }
            else
            {
                break;
            }
        }

        // 检查垂直匹配
        var verticalMatches = new List<Tile> { tile };

        // 向上检查
        for (var y = (int)gridPos.Y - 1; y >= 0; y--)
        {
            var otherTile = _tiles[(int)gridPos.X, y];
            if (otherTile != null && otherTile.Type == tile.Type)
            {
                verticalMatches.Add(otherTile);
            }
            else
            {
                break;
            }
        }

        // 向下检查
        for (var y = (int)gridPos.Y + 1; y < GridHeight; y++)
        {
            var otherTile = _tiles[(int)gridPos.X, y];
            if (otherTile != null && otherTile.Type == tile.Type)
            {
                verticalMatches.Add(otherTile);
            }
            else
            {
                break;
            }
        }

        // 如果水平匹配大于等于3，添加到结果
        if (horizontalMatches.Count >= 3)
        {
            matches.AddRange(horizontalMatches);
        }

        // 如果垂直匹配大于等于3，添加到结果
        if (verticalMatches.Count >= 3)
        {
            foreach (var match in verticalMatches)
            {
                if (!matches.Contains(match))
                {
                    matches.Add(match);
                }
            }
        }

        return matches;
    }

    private async System.Threading.Tasks.Task RemoveMatches(List<Tile> matches)
    {
        foreach (var tile in matches)
        {
            // 播放消除动画
            var tween = CreateTween();
            tween.TweenProperty(tile, "scale", Vector2.Zero, 0.2f);
            await ToSignal(tween, "finished");

            tile.Type = TileType.None;
            tile.Scale = Vector2.One;
        }
    }

    private async System.Threading.Tasks.Task FillEmptySpaces()
    {
        // 下落现有方块
        for (var x = 0; x < GridWidth; x++)
        {
            for (var y = GridHeight - 1; y >= 0; y--)
            {
                if (_tiles[x, y].Type == TileType.None)
                {
                    // 寻找上方第一个非空方块
                    for (var ny = y - 1; ny >= 0; ny--)
                    {
                        if (_tiles[x, ny].Type != TileType.None)
                        {
                            // 移动方块
                            _tiles[x, y].Type = _tiles[x, ny].Type;
                            _tiles[x, ny].Type = TileType.None;

                            // 动画
                            var tween = CreateTween();
                            tween.TweenProperty(_tiles[x, y], "position", GetPositionFromGrid(new Vector2(x, y)), 0.3f);
                            await ToSignal(tween, "finished");

                            break;
                        }
                    }
                }
            }
        }

        // 生成新方块
        var random = new Random();
        for (var x = 0; x < GridWidth; x++)
        {
            for (var y = 0; y < GridHeight; y++)
            {
                if (_tiles[x, y].Type == TileType.None)
                {
                    _tiles[x, y].Type = (TileType)random.Next(1, Enum.GetValues(typeof(TileType)).Length);
                    _tiles[x, y].Position = GetPositionFromGrid(new Vector2(x, y - 1));

                    // 下落动画
                    var tween = CreateTween();
                    tween.TweenProperty(_tiles[x, y], "position", GetPositionFromGrid(new Vector2(x, y)), 0.3f);
                    await ToSignal(tween, "finished");
                }
            }
        }
    }
}